﻿namespace Pibby.Core
{
	using System.Diagnostics;	
	
	/// <summary>
	/// Simplest possible implementation of programming by contract, with some enhancements to allow
	/// configurable levels of contract.
	/// Contracts are made up of two parts, the creation of the contract with the condition 
	/// and the "what happens" when it is broken.
	/// </summary>
	public sealed class Contract
	{
		#region Constructors

		private Contract(bool condition)
			: this(condition, string.Empty)
		{
		}

		private Contract(bool condition, string message)
		{
			this.EvaluationResult = condition;
			this.Message = message;
		}

		#endregion

		#region Attributes

		private bool EvaluationResult
		{
			get;
			set;
		}

		private string Message
		{
			get;
			set;
		}

		#endregion

		#region Public Static Methods

		public static void EnsureThat(bool condition)
		{
			new Contract(condition).Check();
		}

		public static void EnsureThat(bool condition, string msg)
		{
			new Contract(condition, msg).Check();
		}

		public static void EnsureIsNotNull(object value)
		{
			new Contract(value != null).Check();
		}

		public static void EnsureIsNotNull(object value, string msg)
		{
			new Contract(value != null, msg).Check();
		}

		public static void EnsureIsNotNullOrEmpty(string value)
		{
			new Contract(!string.IsNullOrEmpty(value)).Check();
		}

		public static void EnsureIsNotNullOrEmpty(string value, string msg)
		{
			new Contract(!string.IsNullOrEmpty(value), msg).Check();
		}

		public static void EnsureEqual(int value1, int value2, string msg)
		{
			new Contract(value1 == value2, msg).Check();
		}

		#endregion

		private void Check()
		{
			if (!this.EvaluationResult)
			{
				this.ThrowException();
			}
		}

		[Conditional("DEBUG")]
		private void ThrowException()
		{
			throw new ContractFailureException(this.Message);
		}
	}
}
